Модуль:Карточка
-- Модуль для реализации шаблона -- local p = {} local HtmlBuilder = require('Module:HtmlBuilder') local args = {} local origArgs local argsAliases = {} local root local function union(t1, t2) -- Возвращает объединение значений двух таблиц в виде последовательности. local vals = {} for k, v in pairs(t1) do valsv = true end for k, v in pairs(t2) do valsv = true end local ret = {} for k, v in pairs(vals) do table.insert(ret, k) end return ret end local function getArgNums(prefix) -- Возвращает таблицу индексов существующих полей с заданным префиксом, -- например, для префикса 'текст' и установленных 'текст1', 'текст2' и -- 'текст5' возвращает {1, 2, 5}. local nums = {} for k, v in pairs(args) do local num = tostring(k):match('^' .. prefix .. '(1-9%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end local function addRow(rowArgs) -- Добавляет строку в карточку (заголовок или метку/текст). if rowArgs.header then root .tag('tr') .addClass(rowArgs.rowclass) .attr('id', rowArgs.rowid) .tag('th') .attr('colspan', 2) .attr('id', rowArgs.headerid) .addClass(rowArgs.class) .addClass(args'класс_заголовков') .css('text-align', 'center') .cssText(args'стиль_заголовков') .wikitext(rowArgs.header) elseif rowArgs.data then local row = root.tag('tr') row.addClass(rowArgs.rowclass) row.attr('id', rowArgs.rowid) if rowArgs.label then row .tag('th') .attr('scope', 'row') .attr('id', rowArgs.labelid) .cssText(args'стиль_меток') .wikitext(rowArgs.label) .done() end local dataCell = row.tag('td') if not rowArgs.label then dataCell .attr('colspan', 2) .css('text-align', 'center') end dataCell .attr('id', rowArgs.dataid) .addClass(rowArgs.class) .cssText(rowArgs.datastyle) .newline() .wikitext(rowArgs.data) end end local function renderTitle() if not args'название' then return end root .tag('caption') .addClass(args'класс_названия') .cssText(args'стиль_названия') .wikitext(args'название') end local function renderAboveRow() if not args'вверху' then return end root .tag('tr') .tag('th') .attr('colspan', 2) .addClass(args'класс_вверху') .css('text-align', 'center') .css('font-size', '125%') .css('font-weight', 'bold') .cssText(args'стиль_вверху') .wikitext(args'вверху') end local function renderAbove2Row() if not args'вверху2' then return end root .tag('tr') .tag('th') .attr('colspan', 2) .addClass(args'класс_вверху2') .css('text-align', 'center') .css('font-style', 'oblique') .cssText(args'стиль_вверху2') .wikitext(args'вверху2') end local function renderBelowRow() if not args'внизу' then return end root .tag('tr') .tag('td') .attr('colspan', 2) .addClass(args'класс_внизу') .css('text-align', 'center') .cssText(args'стиль_внизу') .newline() .wikitext(args'внизу') end local function renderSubheaders() if args'подзаголовок' then args'подзаголовок1' = args'подзаголовок' end if args'класс_ряда_подзаголовка' then args'класс_ряда_подзаголовка1' = args'класс_ряда_подзаголовка' end local subheadernums = getArgNums('подзаголовок') for k, num in ipairs(subheadernums) do addRow({ data = args.. tostring(num), datastyle = args'стиль_подзаголовков' or args.. tostring(num), class = args'класс_подзаголовков', rowclass = args.. tostring(num) }) end end local function renderImages() if args'изображение' then args'изображение1' = args'изображение' end if args'подпись' then args'подпись1' = args'подпись' end local imagenums = getArgNums('изображение') for k, num in ipairs(imagenums) do local caption = args.. tostring(num) local data = HtmlBuilder.create().wikitext(args.. tostring(num)) if caption then data .tag('div') .cssText(args'стиль_подписи') .wikitext(caption) end addRow({ data = tostring(data), datastyle = args'стиль_изображения', class = args'класс_изображения', rowclass = args.. tostring(num) }) end end local function renderRows() -- Объединяет индексы заголовков и текстовых строк карточки -- и визуализирует их в правильном порядке через addRow. local rownums = union(getArgNums('заголовок'), getArgNums('текст')) table.sort(rownums) for k, num in ipairs(rownums) do addRow({ header = args.. tostring(num), label = args.. tostring(num), data = args.. tostring(num), datastyle = args'стиль_текста', class = args.. tostring(num), rowclass = args.. tostring(num), dataid = args.. tostring(num), labelid = args.. tostring(num), headerid = args.. tostring(num), rowid = args.. tostring(num) }) end end local function renderNavBar() if not args'имя' then return end root .tag('tr') .tag('td') .attr('colspan', 2) .css('text-align', 'right') .wikitext(mw.getCurrentFrame():expandTemplate({ title = 'Tnavbar', args = { args'имя' } })) end local function isSet(x) -- Возвращает истину, если x задан и не пустой -- Внимание: отличается от enwiki! В enwiki проверяется на равенство 'yes' return x and x ~= '' end local function renderItalicTitle() -- Внимание: отличается от enwiki. В enwiki ожидается yes или force, здесь работает любое значение if isSet(args'заголовок_курсивом') then root.wikitext(mw.getCurrentFrame():expandTemplate({title = 'Заголовок курсивом'})) end end local function renderTrackingCategories() if not isSet(args.nocat) then if #(getArgNums('текст')) 0 and mw.title.getCurrentTitle().namespace 0 then root.wikitext('Категория:Статьи с карточкой без заполненных данных') end if isSet(args'внедрение') and args'название' then root.wikitext('Категория:Статьи со встроенной карточкой и параметром названия') end end end local function _infobox() -- Задание общей страктуры карточки с добавлением стилей -- для карточек-потомков. if not isSet(args'внедрение') then root = HtmlBuilder.create('table') root .addClass('infobox') .addClass(args'класс_тела') if isSet(args'подкарточка') then root .css('padding', '0') .css('border', 'none') .css('margin', '-2px') .css('width', 'auto') .css('min-width', '100%') .css('font-size', '100%') .css('clear', 'none') .css('float', 'none') .css('background-color', 'transparent') end -- Микроразметка if isSet(args'микр_тела') then root .attr('itemscope', 'itemscope') .attr('itemtype', args'микр_тела') end root .cssText(args'стиль_тела') renderTitle() renderAboveRow() renderAbove2Row() else root = HtmlBuilder.create() root .wikitext(args'название') end renderSubheaders() renderImages() renderRows() renderBelowRow() renderNavBar() renderItalicTitle() renderTrackingCategories() return tostring(root) end local function preprocessSingleArg(argName) -- Добавляет аргумент в таблицу аргументов, если он определён и не пустой. -- Пустые аргументы не обрабатываются, как и в ParserFunctions. if origArgsargName and origArgsargName ~= '' then argsargName = origArgsargName end end local function translateArg(aliasArgName,localArgName) -- Функция добавляет поддержку алиасов параметров (например, на другом языке) -- Добавляем алиас параметра в таблицу алиасов -- Для одного параметра может быть несколько алиасов -- Нумерованные параметры(текст1 и т.д.) заносятся без номера if not argsAliaseslocalArgName then argsAliaseslocalArgName = {} end table.insert(argsAliaseslocalArgName, aliasArgName) -- Пока для тестирования: значения алиасов добавляются в таблицу аргументов -- Нумерованные параметры работать не будут if origArgslocalArgName and origArgslocalArgName ~= '' then -- параметр уже задан на локальном языке else -- если алиас задан и не пустой if origArgsaliasArgName and origArgsaliasArgName ~= '' then origArgslocalArgName = origArgsaliasArgName end end end local function preprocessArgs(prefixTable, step) -- Сохраняет параметры с заданными префиксами в таблицу args, последовательно обходя -- аргументы в нужном порядке и с нужным шагом. Благодаря этому сноски и пр. появляются -- в правильном порядке. prefixTable — массив таблиц, каждая из которых может содержать -- два поля: поле-строку префикса (обязательно) и поле-таблицу зависимых параметров. -- Эта функция всегда обрабатывает параметры с префиксом, но зависимые параметры -- обрабатываются, только если параметр с префиксом задан и не пустой. if type(prefixTable) ~= 'table' then error("В качестве таблицы префиксов должна использоваться таблица", 2) end if type(step) ~= 'number' then error("Недопустимый тип параметра шага", 2) end -- Проверка правильности данных и обработка параметров без суффиксов. for i,v in ipairs(prefixTable) do if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then error('Недопустимая таблица префиксов preprocessArgs', 2) end preprocessSingleArg(v.prefix) -- Зависимые параметры обрабатываются, только если параметр с префиксом задан и не пустой. if argsv.prefix and v.depend then for j, dependValue in ipairs(v.depend) do if type(dependValue) ~= 'string' then error('Недопустимый тип зависимого параметра в таблице preprocessArgs') end preprocessSingleArg(dependValue) end end end -- Обход нумерованных аргументов. local a = 1 -- Переменная-счётчик. local moreArgumentsExist = true while moreArgumentsExist true do moreArgumentsExist = false for i = a, a + step - 1 do for j,v in ipairs(prefixTable) do local prefixArgName = v.prefix .. tostring(i) if origArgsprefixArgName then moreArgumentsExist = true -- Искать аргументы дальше, если был хотя бы один (в т. ч. пустой) preprocessSingleArg(prefixArgName) end -- Обрабатываем зависимые аргументы, если определена таблица зависимостей, -- а также задан не пустой аргумент с префиксом, либо обрабатывается -- "префикс1" и "префикс" задан (например, "изображение1" является синонимом для "изображение"). if v.depend and (argsprefixArgName or (i 1 and argsv.prefix)) then for j,dependValue in ipairs(v.depend) do local dependArgName = dependValue .. tostring(i) preprocessSingleArg(dependArgName) end end end end a = a + step end end function p.infobox(frame) -- При запуске через #invoke аргументы передаются через стандартную систему. -- При тестировании также можно передавать таблицу аргументов через frame. if frame mw.getCurrentFrame() then origArgs = frame:getParent().args else origArgs = frame end -- Поддержка параметров из англовики translateArg('child','внедрение') translateArg('bodyclass','класс_тела') translateArg('subbox','подкарточка') translateArg('bodystyle','стиль_тела') translateArg('title','название') translateArg('titleclass','класс_названия') translateArg('titlestyle','стиль_названия') translateArg('above','вверху') translateArg('aboveclass','класс_вверху') translateArg('abovestyle','стиль_вверху') translateArg('subheader','подзаголовок') translateArg('subheaderstyle','стиль_подзаголовка') translateArg('subheaderrowclass','класс_подзаголовка') translateArg('subheaderstyle','стиль_подзаголовков') translateArg('subheaderclass','класс_подзаголовков') translateArg('image','изображение') translateArg('caption','подпись') translateArg('imagerowclass','класс_ряда_изображения') translateArg('captionstyle','стиль_подписи') translateArg('imagestyle','стиль_изображения') translateArg('imageclass','класс_изображения') translateArg('header','заголовок') translateArg('data','текст') translateArg('label','метка') translateArg('rowclass','класс_ряда') translateArg('class','класс') translateArg('dataid','id_текста') translateArg('labelid','id_метки') translateArg('headerid','id_заголовка') translateArg('rowid','id_ряда') translateArg('headerclass','класс_заголовков') translateArg('headerstyle','стиль_заголовков') translateArg('labelstyle','стиль_меток') translateArg('datastyle','стиль_текста') translateArg('below','внизу') translateArg('belowclass','класс_внизу') translateArg('belowstyle','стиль_внизу') translateArg('name','имя') --translateArg('italic title','заголовок_курсивом') --translateArg(,) -- Параметры обрабатываются по направлению чтения карточки, чтобы -- сноски и др. отображались в нужных местах. Параметры, зависящие -- от других параметров, обрабатываются только при наличии других параметров, -- чтобы в списке сносок не возникали нежелательные сноски. preprocessSingleArg('внедрение') preprocessSingleArg('класс_тела') preprocessSingleArg('подкарточка') preprocessSingleArg('стиль_тела') preprocessSingleArg('название') preprocessSingleArg('класс_названия') preprocessSingleArg('стиль_названия') preprocessSingleArg('вверху') preprocessSingleArg('класс_вверху') preprocessSingleArg('стиль_вверху') preprocessSingleArg('вверху2') preprocessSingleArg('класс_вверху2') preprocessSingleArg('стиль_вверху2') preprocessArgs({ {prefix = 'подзаголовок', depend = {'стиль_подзаголовка', 'класс_подзаголовка'}} }, 10) preprocessSingleArg('стиль_подзаголовков') preprocessSingleArg('класс_подзаголовков') preprocessArgs({ {prefix = 'изображение', depend = {'подпись', 'класс_ряда_изображения'}} }, 10) preprocessSingleArg('стиль_подписи') preprocessSingleArg('стиль_изображения') preprocessSingleArg('класс_изображения') preprocessArgs({ {prefix = 'заголовок'}, {prefix = 'текст', depend = {'метка'}}, {prefix = 'класс_ряда'}, {prefix = 'класс'}, {prefix = 'id_текста'}, {prefix = 'id_метки'}, {prefix = 'id_заголовка'}, {prefix = 'id_ряда'} }, 50) preprocessSingleArg('класс_заголовков') preprocessSingleArg('стиль_заголовков') preprocessSingleArg('стиль_меток') preprocessSingleArg('стиль_текста') preprocessSingleArg('внизу') preprocessSingleArg('класс_внизу') preprocessSingleArg('стиль_внизу') preprocessSingleArg('имя') preprocessSingleArg('заголовок_курсивом') preprocessSingleArg('nocat') return _infobox() end return p